#!/bin/bash
#
# ==============================================================================
# Oracle 表空间手动扩容脚本 (交互式) - v2
#
# 描述: 此脚本首先检查是否由特权用户 ('root' 或 'oracle') 运行，
#       然后通过交互式提示获取详细信息，为指定的表空间添加一个新的数据文件。
#
# 兼容性: Oracle 11g, 12c, 19c, 21c
# 作者: Gemini
#
# 用法:
# 1. 将脚本保存为 'auto_expand_tbs.sh'。
# 2. 授予执行权限: chmod +x auto_expand_tbs.sh
# 3. 以 'root' 或 'oracle' 用户身份运行:
#    - sudo ./auto_expand_tbs.sh
#    - 或 (以 oracle 用户身份): ./auto_expand_tbs.sh
# 4. 执行方式：bash <(curl -s -L https://gitee.com/securitypass/auto-scirpt/raw/master/oracle/auto_expand_tbs.sh)
# ==============================================================================

# --- CONFIGURATION ---
# ------------------------------------------------------------------------------
# 您可以根据需要调整以下这些通用设置

# 每次自动扩容时新增的数据文件大小 (单位: MB)
ADD_MB_SIZE=512

# 新数据文件的最大允许大小 (单位: GB)
MAX_SIZE_GB=32

# Oracle 软件所有者的操作系统用户名
ORACLE_USER="oracle"

# --- END OF CONFIGURATION ---
# ------------------------------------------------------------------------------


# --- SCRIPT LOGIC (DO NOT MODIFY BELOW THIS LINE) ---

# 1. 优先检查当前用户身份
CURRENT_USER=$(whoami)

if [[ "${CURRENT_USER}" == "root" ]]; then
    # --- 以 ROOT 用户身份执行 ---
    echo "--- Oracle 表空间手动扩容脚本 ---"
    echo "信息: 检测到 root 用户，将切换到 '${ORACLE_USER}' 用户执行..."
    echo "-----------------------------------------------------"

    # a. 获取用户输入
    read -p "请输入 Oracle SID: " ORACLE_SID
    read -p "请输入要扩容的表空间名称 (请使用大写): " TABLESPACE_NAME
    read -p "请输入新数据文件的存放目录 (例如: /u01/app/oracle/oradata/orcl): " DATAFILE_DIR

    # b. 验证输入
    if [[ -z "${ORACLE_SID}" || -z "${TABLESPACE_NAME}" || -z "${DATAFILE_DIR}" ]]; then
        echo "错误: SID、表空间名称和数据文件目录均不能为空。"
        exit 1
    fi
    if [ ! -d "${DATAFILE_DIR}" ]; then
        echo "错误: 数据文件目录 '${DATAFILE_DIR}' 不存在或不是一个目录。"
        exit 1
    fi

    # c. 切换用户并执行命令
    su - ${ORACLE_USER} <<EOF
    # 在 su 会话中设置 Oracle 环境变量
    export ORACLE_SID=${ORACLE_SID}
    ORACLE_HOME_GUESS=\$(grep "^${ORACLE_SID}:" /etc/oratab | cut -d: -f2)
    if [ -n "\${ORACLE_HOME_GUESS}" ] && [ -d "\${ORACLE_HOME_GUESS}" ]; then
        export ORACLE_HOME=\${ORACLE_HOME_GUESS}
    else
        echo "警告: 无法从 /etc/oratab 自动确定 ORACLE_HOME。请确保环境变量已正确设置。"
    fi
    export PATH=\$ORACLE_HOME/bin:\$PATH

    # 检查数据库连接
    tnsping \${ORACLE_SID} > /dev/null 2>&1
    if [ \$? -ne 0 ]; then
        echo "错误: 无法连接到数据库 '\${ORACLE_SID}'。请检查监听器状态和环境变量。"
        exit 1
    fi
    echo "信息: 成功设置环境，准备连接数据库..."

    # 执行 SQL*Plus 命令
    sqlplus -s / as sysdba <<SQL
        SET SERVEROUTPUT ON;
        SET HEADING OFF;
        SET FEEDBACK OFF;
        WHENEVER SQLERROR EXIT SQL.SQLCODE;
        DECLARE
            v_tablespace_name   VARCHAR2(30)  := UPPER('${TABLESPACE_NAME}');
            v_add_mb            NUMBER        := ${ADD_MB_SIZE};
            v_datafile_dir      VARCHAR2(256) := '${DATAFILE_DIR}';
            v_max_gb            NUMBER        := ${MAX_SIZE_GB};
            v_new_datafile_name VARCHAR2(512);
            v_sql               VARCHAR2(1000);
            v_datafile_count    NUMBER;
            v_tbs_exists        NUMBER;
        BEGIN
            SELECT COUNT(*) INTO v_tbs_exists FROM dba_tablespaces WHERE tablespace_name = v_tablespace_name;
            IF v_tbs_exists = 0 THEN
                DBMS_OUTPUT.PUT_LINE('错误: 表空间 "' || v_tablespace_name || '" 不存在。请检查您的输入。');
                RETURN;
            END IF;
            DBMS_OUTPUT.PUT_LINE('信息: 准备为表空间 ' || v_tablespace_name || ' 添加新的数据文件...');
            SELECT COUNT(*) + 1 INTO v_datafile_count FROM dba_data_files WHERE tablespace_name = v_tablespace_name;
            v_new_datafile_name := v_datafile_dir || '/' || LOWER(v_tablespace_name) || LPAD(v_datafile_count, 2, '0') || '.dbf';
            DBMS_OUTPUT.PUT_LINE('信息: 新数据文件路径: ' || v_new_datafile_name);
            v_sql := 'ALTER TABLESPACE ' || v_tablespace_name ||
                     ' ADD DATAFILE ''' || v_new_datafile_name ||
                     ''' SIZE ' || v_add_mb || 'M AUTOEXTEND ON NEXT 256M MAXSIZE ' || v_max_gb || 'G';
            DBMS_OUTPUT.PUT_LINE('执行SQL: ' || v_sql);
            EXECUTE IMMEDIATE v_sql;
            DBMS_OUTPUT.PUT_LINE('成功: 表空间 ' || v_tablespace_name || ' 已成功扩容。');
        EXCEPTION
            WHEN OTHERS THEN
                DBMS_OUTPUT.PUT_LINE('严重错误: 在扩容过程中发生异常。');
                DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
                DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
                RAISE;
        END;
        /
        EXIT;
SQL
EOF

elif [[ "${CURRENT_USER}" == "${ORACLE_USER}" ]]; then
    # --- 以 ORACLE 用户身份直接执行 ---
    echo "--- Oracle 表空间手动扩容脚本 ---"
    echo "信息: 检测到 '${ORACLE_USER}' 用户，直接执行..."
    echo "-----------------------------------------------------"

    # a. 获取用户输入
    read -p "请输入 Oracle SID: " ORACLE_SID
    read -p "请输入要扩容的表空间名称 (请使用大写): " TABLESPACE_NAME
    read -p "请输入新数据文件的存放目录 (例如: /u01/app/oracle/oradata/orcl): " DATAFILE_DIR

    # b. 验证输入
    if [[ -z "${ORACLE_SID}" || -z "${TABLESPACE_NAME}" || -z "${DATAFILE_DIR}" ]]; then
        echo "错误: SID、表空间名称和数据文件目录均不能为空。"
        exit 1
    fi
    if [ ! -d "${DATAFILE_DIR}" ]; then
        echo "错误: 数据文件目录 '${DATAFILE_DIR}' 不存在或不是一个目录。"
        exit 1
    fi

    # c. 设置 Oracle 环境变量并执行命令
    export ORACLE_SID=${ORACLE_SID}
    ORACLE_HOME_GUESS=$(grep "^${ORACLE_SID}:" /etc/oratab | cut -d: -f2)
    if [ -n "${ORACLE_HOME_GUESS}" ] && [ -d "${ORACLE_HOME_GUESS}" ]; then
        export ORACLE_HOME=${ORACLE_HOME_GUESS}
    else
        echo "警告: 无法从 /etc/oratab 自动确定 ORACLE_HOME。请确保环境变量已正确设置。"
    fi
    export PATH=$ORACLE_HOME/bin:$PATH

    # 检查数据库连接
    tnsping ${ORACLE_SID} > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo "错误: 无法连接到数据库 '${ORACLE_SID}'。请检查监听器状态和环境变量。"
        exit 1
    fi
    echo "信息: 成功设置环境，准备连接数据库..."

    # 执行 SQL*Plus 命令
    sqlplus -s / as sysdba <<SQL
        SET SERVEROUTPUT ON;
        SET HEADING OFF;
        SET FEEDBACK OFF;
        WHENEVER SQLERROR EXIT SQL.SQLCODE;
        DECLARE
            v_tablespace_name   VARCHAR2(30)  := UPPER('${TABLESPACE_NAME}');
            v_add_mb            NUMBER        := ${ADD_MB_SIZE};
            v_datafile_dir      VARCHAR2(256) := '${DATAFILE_DIR}';
            v_max_gb            NUMBER        := ${MAX_SIZE_GB};
            v_new_datafile_name VARCHAR2(512);
            v_sql               VARCHAR2(1000);
            v_datafile_count    NUMBER;
            v_tbs_exists        NUMBER;
        BEGIN
            SELECT COUNT(*) INTO v_tbs_exists FROM dba_tablespaces WHERE tablespace_name = v_tablespace_name;
            IF v_tbs_exists = 0 THEN
                DBMS_OUTPUT.PUT_LINE('错误: 表空间 "' || v_tablespace_name || '" 不存在。请检查您的输入。');
                RETURN;
            END IF;
            DBMS_OUTPUT.PUT_LINE('信息: 准备为表空间 ' || v_tablespace_name || ' 添加新的数据文件...');
            SELECT COUNT(*) + 1 INTO v_datafile_count FROM dba_data_files WHERE tablespace_name = v_tablespace_name;
            v_new_datafile_name := v_datafile_dir || '/' || LOWER(v_tablespace_name) || LPAD(v_datafile_count, 2, '0') || '.dbf';
            DBMS_OUTPUT.PUT_LINE('信息: 新数据文件路径: ' || v_new_datafile_name);
            v_sql := 'ALTER TABLESPACE ' || v_tablespace_name ||
                     ' ADD DATAFILE ''' || v_new_datafile_name ||
                     ''' SIZE ' || v_add_mb || 'M AUTOEXTEND ON NEXT 256M MAXSIZE ' || v_max_gb || 'G';
            DBMS_OUTPUT.PUT_LINE('执行SQL: ' || v_sql);
            EXECUTE IMMEDIATE v_sql;
            DBMS_OUTPUT.PUT_LINE('成功: 表空间 ' || v_tablespace_name || ' 已成功扩容。');
        EXCEPTION
            WHEN OTHERS THEN
                DBMS_OUTPUT.PUT_LINE('严重错误: 在扩容过程中发生异常。');
                DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
                DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
                RAISE;
        END;
        /
        EXIT;
SQL

else
    # --- 用户不正确 ---
    echo "错误: 此脚本必须由 'root' 或 '${ORACLE_USER}' 用户运行。"
    echo "当前用户是: ${CURRENT_USER}"
    exit 1
fi

echo "-----------------------------------------------------"
echo "脚本执行完毕。"
echo "-----------------------------------------------------"
